home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / WINSOCK.PAK / DLGDGRM.CPP < prev    next >
C/C++ Source or Header  |  1997-05-06  |  10KB  |  270 lines

  1. /*-----------------------------------------------------------------------*\
  2. | OWLSock Demo For Windows v1.0                                           |
  3. --------------------------------------------------------------------------|
  4. | Written By:  Paul Pedriana                                              |
  5. | Date:        May 7, 1995.                                               |
  6. | Copyright:   Copyright (c) 1995 by Paul Pedriana.  All Rights Reserved. |
  7. | UserID(s):   70541,3223                                                 |
  8. |              70541.3223@compuserve.com                                  |
  9. --------------------------------------------------------------------------|
  10. | This OWLSock demo is an application that demonstrates some features     |
  11. | of OWLSock.  It uses only asynchronous (non-blocking) Winsock calls,    |
  12. | and uses OWLSock socket 'external' notification rather than internal    |
  13. | notification.  External notification is the way most Winsock apps do    |
  14. | FD_XXX notifications; see the OWLSock docs for more info.               |
  15. --------------------------------------------------------------------------|
  16. | Notes on this module:                                                   |
  17. |    This module is a dialog box that implements a datagram socket UDP    |
  18. | data sender and receiver.  You simply specify a port and address, and   |
  19. | it makes a socket to match and sends the data you request to the given  |
  20. | port and address.  Currently, this dialog only keeps the socket open    |
  21. | as long as it is sending data, so it would be hard to run another       |
  22. | instance of this dialog an another machine to receive the data.         | 
  23. \*-----------------------------------------------------------------------*/
  24.  
  25. #include <owl/pch.h>
  26. #if !defined(OWL_WINSOCK_H)
  27. # include <owl/winsock.h>
  28. #endif
  29. #include <stdlib.h>        //For atoi() call.
  30. #include "dlgdgrm.h"
  31.  
  32. //********************************************************************************************
  33. DEFINE_RESPONSE_TABLE1(DlgSendDatagram, TDialog)
  34.   EV_CHILD_NOTIFY(IDC_BTN_SEND, BN_CLICKED, CmBtnSend),
  35.   EV_CHILD_NOTIFY(IDC_BTN_SEND_CLEAR, BN_CLICKED, CmBtnSendClear),
  36.   EV_CHILD_NOTIFY(IDC_BTN_RECEIVE_CLEAR, BN_CLICKED, CmBtnReceiveClear),
  37.   EV_MESSAGE(MSG_HOST_INFO_NOTIFY, DoHostNotification),
  38.   EV_MESSAGE(MSG_SOCKET_NOTIFY, DoSocketNotification),
  39. END_RESPONSE_TABLE;
  40.  
  41. DlgSendDatagram::DlgSendDatagram(TWindow *parent, TResId resId, TModule *module)
  42. :
  43.   TDialog(parent, resId, module),
  44.   myPresentState(nIdle),
  45.   sAddressToSendTo(0, INADDR_NONE),
  46.   bDataSent(true)
  47. {
  48.   TINetSocketAddress ourSocketAddress; //same as TINetSocketAddress(0, INADDR_ANY);
  49.  
  50.   myPresentState = nIdle;
  51.   myDatagramSocket = new TDatagramSocket(ourSocketAddress);
  52.   myDatagramSocket->SetNotificationWindow(this); //redirect socket FD_XXX notifications to us.
  53. }
  54.  
  55.  
  56. DlgSendDatagram::~DlgSendDatagram()
  57. {
  58.   delete myDatagramSocket;
  59. }
  60.  
  61.  
  62. void DlgSendDatagram::SetupWindow()
  63. {
  64.   editAddressSend    = new TEdit(this, IDC_EDIT_ADDRESS_SEND,    64);
  65.   editAddressReceive = new TEdit(this, IDC_EDIT_ADDRESS_RECEIVE, 64);
  66.   editDataSend       = new TEdit(this, IDC_EDIT_SEND,            256);
  67.   editDataReceive    = new TEdit(this, IDC_EDIT_RECEIVE,         256);
  68.   editPort           = new TEdit(this, IDC_EDIT_PORT,            8);
  69.   staticStatus       = new TStatic(this, IDC_STATIC_STATUS,      32);
  70.   TDialog::SetupWindow();
  71. }
  72.  
  73.  
  74. LRESULT DlgSendDatagram::DoHostNotification(WPARAM, LPARAM lParam)
  75. {
  76.   int  nError = WSAGETASYNCERROR(lParam);
  77.  
  78.   if (myPresentState != nWaitingForAddress)
  79.     return 1;
  80.  
  81.   if (nError){
  82.     MessageBox(TSocketError(nError).AppendError("Error on looking up address."), "Error", MB_OK);
  83.     GoToIdleState();
  84.   }
  85.   else {
  86.     sAddressToSendTo.SetNetworkAddress(myHostInfoManager.HostEntry->GetINetAddress());
  87.     GoToSendingDataState();
  88.     SendData();
  89.   }
  90.   return 1;
  91. }
  92.  
  93.  
  94. LRESULT DlgSendDatagram::DoSocketNotification(WPARAM, LPARAM lParam)
  95. {
  96.   int nEvent = (int)WSAGETSELECTEVENT(lParam);
  97.   int nError = (int)WSAGETSELECTERROR(lParam);
  98.  
  99.   if (nEvent == FD_WRITE  && !nError && myPresentState == nSendingData && !bDataSent)
  100.     SendData();
  101.  
  102.   else if (nEvent == FD_READ && !nError)
  103.     ReadData();
  104.  
  105.   return 1L;
  106. }
  107.  
  108.  
  109.  
  110. void DlgSendDatagram::ReadData()
  111. {
  112.   char         chData[256]; //For demo purposes, we only accept small amounts of data.
  113.   int          nLength=255;
  114.   char far*    szAddress;
  115.   TINetSocketAddress sAddress;
  116.  
  117.   int error = myDatagramSocket->Read(chData, nLength, sAddress);
  118.   if (error == WINSOCK_ERROR){
  119.     MessageBox(TSocketError(myDatagramSocket->GetLastError()).GetReasonString(),
  120.                "FD_READ Error", MB_OK);
  121.     return;
  122.   }
  123.   chData[nLength] = 0; //Null-terminate the data to make it a C-string.
  124.   szAddress = sAddress.ConvertAddress(sAddress.GetNetworkAddress());
  125.   editAddressReceive->SetWindowText(szAddress);
  126.   editDataReceive->SetWindowText(chData);
  127. }
  128.  
  129. void DlgSendDatagram::SendData()
  130. {
  131.   int charsToSend = strlen(szDataToSend);
  132.   int error = myDatagramSocket->Write(szDataToSend, charsToSend, sAddressToSendTo);
  133.   if (error == WINSOCK_ERROR) {
  134.     if (myDatagramSocket->GetLastError() == WSAEWOULDBLOCK)
  135.       return; //leave state at: myPresentState = nSendingData
  136.     bDataSent = TRUE;
  137.     MessageBox(TSocketError(myDatagramSocket->GetLastError()).GetReasonString(),
  138.                "Send Failed", MB_OK);
  139.     GoToIdleState();
  140.     return;
  141.   }
  142.   // It is important that we set the bDataSent flag to be true here,
  143.   //  before we call MessageBox(), because MessageBox() will let another
  144.   //  FD_WRITE message be received, and while the MessageBox() is up, we
  145.   //  will inadvertantly send data again.
  146.   // Note that if we remove the MessageBox() statement and simply call
  147.   //  GoToIdleState(), the socket will be immediately closed.  Immediately
  148.   //  closing a socket right after sending data could lose the sent data
  149.   //  unless the socket is set to linger.
  150.   bDataSent = true;
  151.   MessageBox("Send succeeded\n\nClick OK to close the socket. Closing the socket will disable"
  152.           " the ability to receive data on the given port.  This datagram sender creates"
  153.           " a socket on the fly when you click 'send' and closes the socket when you click"
  154.           " on this OK box.  However, you can receive data while this message box remains open.",
  155.           "", MB_OK);
  156.   GoToIdleState();
  157. }
  158.  
  159. void DlgSendDatagram::CmBtnSend()
  160. {
  161.   short  bAddressIsDottedDecimal;
  162.   char   szAddressInput[256];
  163.   HANDLE  hHostRequest;
  164.   int    nError;
  165.   u_short nPort;
  166.   char   szPort[8];
  167.  
  168.   if (myPresentState != nIdle){
  169.     MessageBox("Busy Sending Data Already", "", MB_OK);
  170.     return;
  171.   }
  172.  
  173.   //Set up port
  174.   editPort->GetWindowText(szPort, 7);
  175.   nPort = TWinSock::Dll()->htons((u_short)atoi(szPort)); //you may get a compiler warning here.
  176.   sAddressToSendTo.SetPort(nPort);
  177.  
  178.   //Set up socket
  179.   nError = myDatagramSocket->CreateSocket(); //similar to 'socket()'
  180.   if (nError == WINSOCK_ERROR){ //could also say 'if (nError){'
  181.     MessageBox(TSocketError(myDatagramSocket->GetLastError()).AppendError("Error on CreateSocket()"), "Error", MB_OK);
  182.     GoToIdleState();
  183.     return;
  184.   }
  185.  
  186.   ////Turn on/off lingering, if you want.
  187.   //myDatagramSocket->SetLingerOption(FALSE);   //Don't linger on closesocket().  Not important here.
  188.  
  189.   //Make the sock asynchronous and notify us.  
  190.   myDatagramSocket->StartRegularNotification();  //similar to 'WSAAsyncSelect()'
  191.  
  192.   //Bind the socket to our address and port.
  193.   //By binding to a specific port, we can receive datagrams on the same port as we send them.
  194.   //  We thus can even send datagrams to ourselves if we want to.
  195.   myDatagramSocket->SetMyAddress(TINetSocketAddress(nPort));
  196.   nError = myDatagramSocket->BindSocket(); //similar to 'bind()'
  197.   if (nError == WINSOCK_ERROR){ //could also say 'if (nError){'
  198.     MessageBox(TSocketError(myDatagramSocket->GetLastError()).AppendError("Error on BindSocket()"), "Error", MB_OK);
  199.     GoToIdleState();
  200.     return;
  201.   }
  202.  
  203.   editDataSend->GetWindowText(szDataToSend, 256);
  204.   if (szDataToSend[0]){
  205.     bDataSent = FALSE;
  206.     GoToWaitingForAddressState();
  207.     editAddressSend->GetWindowText(szAddressInput, 255);
  208.     bAddressIsDottedDecimal = TINetSocketAddress::IsAddressDottedDecimal(szAddressInput);
  209.     if (bAddressIsDottedDecimal) {
  210.       sAddressToSendTo.SetNetworkAddress(sAddressToSendTo.ConvertAddress(szAddressInput));
  211.       GoToSendingDataState();
  212.       SendData();
  213.     }
  214.     else{
  215.       nError = myHostInfoManager.GetHostInfoAsync(*this, hHostRequest, szAddressInput);
  216.       if (nError == WINSOCK_ERROR){
  217.         MessageBox("Unable to convert the host name to an address", "Error", MB_OK);
  218.         GoToIdleState();
  219.       }
  220.     }
  221.   }
  222. }
  223.  
  224.  
  225. void DlgSendDatagram::CmBtnSendClear(){
  226.   editDataSend->SetWindowText(""); //Clear the text.
  227. }
  228.  
  229.  
  230. void DlgSendDatagram::CmBtnReceiveClear(){
  231.   editDataReceive->SetWindowText(""); //Clear the text.
  232. }
  233.  
  234.  
  235. void DlgSendDatagram::CmOk(){
  236.   if (myPresentState == nWaitingForAddress)
  237.     myHostInfoManager.CancelHostRequest();
  238.   if (myPresentState != nIdle)
  239.     GoToIdleState();
  240.   TDialog::CmOk();
  241. }
  242.  
  243.  
  244. void DlgSendDatagram::GoToIdleState(){
  245.   bDataSent = 1;
  246.   myPresentState = nIdle;
  247.   staticStatus->SetWindowText("Status: Idle");
  248.   editPort->SetReadOnly(FALSE);
  249.  
  250.   //We close the socket here if it was open already.
  251.   myDatagramSocket->CloseSocket();
  252. }
  253.  
  254.  
  255. void DlgSendDatagram::GoToWaitingForAddressState(){
  256.   myPresentState = nWaitingForAddress;
  257.   staticStatus->SetWindowText("Status: Looking Up Address...");
  258.   editPort->SetReadOnly(TRUE);
  259. }
  260.  
  261.  
  262. void DlgSendDatagram::GoToSendingDataState(){
  263.   myPresentState = nSendingData;
  264.   staticStatus->SetWindowText("Status: Sending Data");
  265.   editPort->SetReadOnly(TRUE);
  266. }
  267.  
  268.  
  269.  
  270.